<?php
/**
 * 报表计算任务类(业务类)
 *   
 * @author wenqiang@6rooms.com
 * @version $Id: Task.php,v 1.0 2013/11/5 14:14:48 gaowenqiang Exp $   
 * @package service   
 *
 */
class Sr_Service_Task extends Sr_Service_Base
{
	const STAT_TYPE_DAY = 1;// 按天统计
	const STAT_TYPE_HOUR = 2;// 按小时统计
	const STAT_TYPE_HALFHOUR = 3;// 按半小时统计
	
	// 秒
	const DATETIME_UNIT_DAY = 86400; //24 * 60 * 60;
	const DATETIME_UNIT_HOUR = 3600;// 60 * 60
	const DATETIME_UNIT_HALFHOUR = 1800;// 30 * 60
	// 内部参数项
	protected $fields = array(	'type',
								'start',
								'end',
								'input',
								'items');
	public function __construct($items)
	{
		parent::__construct(array('items' => $items));
	}

	protected function init($options)
	{
		parent::init($options);
			
		
		$this->addFields($this->fields);
	}
	
	/**
	 * 获取表单参数
	 *
	 * @param array $form
	 *
	 */
	protected function getFormParams($form)
	{		
		$input = array();
		foreach($fields as $field) {
			$input[$field] = isset($form[$field]) ? $form[$field] : null;
		}

		return $input;
	}

	/**
	 * 参数配置
	 *
	 * @param int $type 报表统计类型
	 * @param 
	 * @param string $start 开始时间
	 * @param string $end 结束时间
	 * @param array $input 附加参数
	 * @param array $items 待计算的报表项
	 * @return bool 
	 *
	 */
	public function setup($form = array())
	{
		// 接收参数
		$input = $this->getFormParams($form);
		// 校验参数
		$validResult = $this->validate($input);
		if (count($validResult['errors'])) {// error
			return false;
		}
		
		$options = $validResult['vars'];
		$this->setOptions($options);
		
		// 创建报表实现类
		$args = array($this->options['type']);
		$prefix = 'Report_';
		$this->report = self::service('calculate', $args, $prefix);
		
		return $this->report ? true : false;
	}
	
	/**
	 * 验证配置参数
     * @param    array $form 配置参数
     * @return   int
     */
	protected function validate($form)
	{
		$now = time();
		// default values
		$default = array(
			'start' => $now,
			'end' => $now,
		);

		$errors = array();
		$vars = array();
		while (1) {
			// type
			if (!isset($form['type']) || !in_array((int)$form['type'], array(self::STAT_TYPE_DAY, 
								  self::STAT_TYPE_HOUR, 
								  self::STAT_TYPE_HALFHOUR)))
			{
				$errors['type'] = 'invalid args(type)';
				break;
			}
			$vars['type'] = (int)$form['type'];

			// check start
			$start = null;
			if (isset($form['start'])) {
				if (strlen($form['start'])) {
					$start = $this->formatParamsByTime($form['start'], $vars['type']);
					if (!$start) {
						$error['start'] = 'invalid args(start)';
						break;
					}
				} else {
					$error['start'] = 'invalid args(start), start can not be empty';
					break;
				}
			} else {
				$start = $default['start'];
			}
		
			// check end
			$end = null;
			if (isset($form['end'])) {
				if (strlen($form['end'])) {
					$end = $this->formatParamsByTime($form['end'], $vars['type']);
					if ($end) {
						$max = $this->maxDatetime();
						if (Hw_Util::datecmp($end, $max) > 0) {
							$error['end'] = 'invalid args(end), end time out of range)';
							break;
							//$end = $max;
						}
					} else {
						$error['end'] = 'invalid args(end)';
						break;
					}
				} else {
					$error['end'] = 'invalid args(end), can not be empty';
					break;
				}
			} else {
				$end = $default['end'];
			}
			
			// check start and end time
			if (Hw_Util::datecmp($start, $end) > 0) {
				$error['time'] = 'invalid args(start), Start time can not exceed the end time';
				break;
			}
			
			// start, end ok
			$vars['start'] = $start;
			$vars['end'] = $end;

			break;
		}

		return array('errors' => $errors, 'vars' => $vars);
	}

	/**
	 * 获取时间间隔秒数
	 *
	 * @param int $type 统计类型
	 * @return int
	 *
	 */
	protected function getUnitTime()
	{
		if (!$type) {
			if (!isset($this->options['type']) && $this->options['type']) {
				$type = $this->options['type'];
			} else {
				return false;
			}
		}

		$second = 0;
		// 添加统计列
		switch ($type) {
			case self::STAT_TYPE_DAY :
				$second = self::DATETIME_UNIT_DAY;
				break;
			case self::STAT_TYPE_HOUR :
				$second = self::DATETIME_UNIT_HOUR;
				break;
			case self::STAT_TYPE_HALFHOUR :
				$second = self::DATETIME_UNIT_HALFHOUR;
				break;
			default:
				break;
		}

		return $second;
	}
	
	/**
	 * 获取最大时间
	 *
	 */
	protected function maxDatetime()
	{
		$now = time();
		return $now;
	}

	
	
	/**
	 * 对输入参数time值进行格式化处理
	 *
	 * @param string $str 输入参数时间字符串
	 * @param int $type 统计类型
	 * @param bool $toString 是否将结果转换为字符串
	 * @return mixed(array|string)
	 *
	 */
	protected function formatParamsByTime($str, $type = null, $toString = true)
	{
		if (!$type) {
			if (!isset($this->options['type']) && $this->options['type']) {
				$type = $this->options['type'];
			} else {
				return false;
			}
		}
		
		if (strpos('#', $str)) {
			$str = strstr('#', ' ', $str);
		}

		$dateStr =
		$tmpStr = explode(' ', $str);
		$dateStr = array(
			'date' => $tmpStr[0], 
			'time' => isset($tmpStr[1]) ? $tmpStr[1]: null
		);

		// validate date
		if (!Hw_Util::isDate($dateStr['date'])) {// 参数错误(日期)
			return false;
		}

		// datetime
		$result = array(
			'date' => null, 
			'time' => null
		);
		$result['date'] = $dateStr['date'];
		switch ($type) {
			case self::STAT_TYPE_DAY :
				$result['time'] = '00:00:00';
				break;
			case self::STAT_TYPE_HOUR :
				$tmpTime = explode(':', $dateStr['time']);
				$dateStr['hour'] = (int)$tmpTime[0];
				
				if (!Hw_Util::isHour($dateStr['hour'])) {// 参数错误(小时)
					return false;
				}
				
				$result['time'] = $dateStr['hour'] . ':00:00';

				break;
			case self::STAT_TYPE_HALFHOUR :
				$tmpTime = explode(':', $dateStr['time']);
				$dateStr['hour'] = (int)$tmpTime[0];
				$dateStr['minute'] = isset($tmpTime[1]) ? (int)$tmpTime[1] : null;
				
				$minuteOptions = array(0, 30);
				if (!in_array($dateStr['minute'], $minuteOptions)) {// 参数错误(分钟)
					return false;
				}
				
				$result['time'] = $dateStr['hour'] . ':' . $dateStr['minute'] . ':00';
				if (!Hw_Util::isTime($result['time'])) {
					return false;
				}

				break;
			default :
				return false;
		}

		return $toString ? $result['date'] . ' ' . $result['time'] : strtotime($result);
	}

	/**
	 * 报表计算
	 *
	 * @param int $type 报表统计类型
     * @return int
	 *
     */
    public function run($type, $params = null)
    {
		// 校验参数并进行基础配置
		$params['type'] = $type;
		if (!$this->setup($params)) {
			return false;
		}

		$time = $this->options['start'];
		while($this->isFinish($time)) {
			// to do ...
			// get end time 
			//$end = 
			$this->reportRun($time);

			$time = $this->nextTime($time);
		}
    }
	
	/**
	 * 任务是否结束
	 *
	 * @param int $time
	 * @return bool
	 *
	 */
	protected function isFinish($time)
	{
		return $time < $this->options['end'];
	}
	
	/**
	 * 获取下次时间
	 *
	 * @param int $time
	 * @return int
	 *
	 */
	protected function nextTime($time)
	{
		$unitTime = $this->getUnitTime();
		return strtotime($time) + $unitTime;
	}
	
	/**
	 * 报表计算开始
	 *
	 * @param int $time 开始时间
	 * @return bool
	 *
	 */
	protected function reportRun($time)
	{
		if (!empty($this->reportItems))
		{
			return false;
		}
		
		$errors = array();
		foreach ($this->reportItems as $item) {
			// report Calculate
			$this->report->setup($item, $time);
			$result = $this->report->begin();
			if (!$result) {
				// log
				$errmsg = "report item: {item}, time: {time}, options: {options}";
				$context = array('item' => $item, 'time' => $time, 'options' => json_encode($this->options));
				$this->error($errmsg, $context);

				$errors[$item] = sprintf("error: %s", $item);
			}
		}

		return count($errors) > 0 ? true : false;
	}

/*
	protected function _convertTimeParam($str1, $str2, $type = null)
	{
		if (!$type) {
			if (!isset($this->options['type']) && $this->options['type']) {
				$type = $this->options['type'];
			} else {
				return false;
			}
		}
		
		if (strpos('#', $str1)) {
			$str1 = strstr('#', ' ', $str1);
		}

		if (strpos('#', $str2)) {
			$str2 = strstr('#', ' ', $str2);
		}
		
		$datetime = array(
			'date' => null, 
			'time' => null
		);

		$datetimeOptions = array(
			'year' => null,
			'month' => null,
			'day' => null,
			'hour' => null,
			'minues' => null,
			'second' => null,
			'date' => null,
			'time' => null,
		);

		$dateStr1 = $datetimeOptions;
		$dateStr2 = $datetimeOptions;
		// str1
		$tmpStr1 = explode(' ', $str1);
		$dateStr1['date'] = $tmpStr1[0];
		$dateStr1['time'] = isset($tmpStr1[1]) ? $tmpStr1[1]: null;
		// end
		$tmpStr2 = explode(' ', $str2);
		$dateStr2['date'] = $tmpStr2[0];
		$dateStr2['time'] = isset($tmpStr2[1]) ? $tmpStr2[1]: null;

		// validate date
		if (!Hw_Util::isDate($dateStr1['date']) || 
				!Hw_Util::isDate($dateStr2['date'])) 
		{// 参数错误(日期)
			return false;
		}
		// start, end datetime
		$start = $datetime;
		$end = $datetime;
		
		$start['date'] = $dateStr1['date'];
		$end['date'] = $dateStr2['date'];

		switch ($type) {
			case self::STAT_TYPE_DAY :
				$start['time'] = '00:00:00';
				$end['time'] = "23:59:59";
				break;
			case self::STAT_TYPE_HOUR :
				$tmpTime1 = explode(':', $dateStr1['time']);
				$dateStr1['hour'] = (int)$tmpTime1[0];

				$tmpTime2 = explode(':', $dateStr2['time']);
				$dateStr2['hour'] = (int)$tmpTime2[0];
				
				
				if (!Hw_Util::isHour($dateStr1['hour']) || 
						Hw_Util::isHour($dateStr2['hour'])) 
				{// 参数错误(小时)
					return false;
				}
				
				$start['time'] = $dateStr1['hour'] . ':00:00';
				$end['time'] = $dateStr2['hour'] . ':00:00';

				break;
			case self::STAT_TYPE_HALFHOUR :
				$tmpTime1 = explode(':', $dateStr1['time']);
				$dateStr1['hour'] = (int)$tmpTime1[0];
				$dateStr1['minute'] = isset($tmpTime1[1]) : (int)$tmpTime1[1] : null;
				
				$tmpTime2 = explode(':', $dateStr2['time']);
				$dateStr2['hour'] = (int)$tmpTime2[0];
				$dateStr2['minute'] = isset($tmpTime2[1]) : (int)$tmpTime2[1] : null;
					
				$minuteOptions = array(0, 30);
				if (!in_array($dateStr1['minute'], $minuteOptions) || 
					!in_array($dateStr2['minute'], $minuteOptions)) 
				{// 参数错误(分钟)
					return false;
				}
				
				$start['time'] = $dateStr1['hour'] . ':' . $dateStr1['minute'] . ':00';
				$end['time'] = $dateStr2['hour'] . ':' . $dateStr2['minute'] . ':00';
				if (!Hw_Util::isTime($start['time']) || !Hw_Util::isTime($end['time'])) {
					return false;
				}

				break;
			default :
				return false;
		}

		return array('start' => $start, 'end' => $end);
	}
*/
	
}
